package heiing.collection.util;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 集合的操作：差集、交集、并集
 * @author heiing
 */
public class CollectionUtils {

    private CollectionUtils() {}

    /**
     * 计算 a 与 b 的 差集，即 a - b。
     * @param <T> 集合的元素类型
     * @param a 集合a
     * @param b 集合b
     * @param supplier 结果集合的类型与集合容器生成方法，例如 LinkedHashSet::new
     * @return 返回  a - b 的结果，如果 b 为空，则返回 a，如果 a 为空，则返回空集
     */
    public static <T> Set<T> subtract(final Set<T> a, final Set<T> b, Supplier<Set<T>> supplier) {
        if (null == a || null == b || b.isEmpty()) {
            return null == a ? Collections.emptySet() : a;
        }
        return a.stream().filter(x -> !b.contains(x)).collect(Collectors.toCollection(supplier));
    }

    /**
     * 计算 a 与 b 的交集
     * @param <T> 集合的元素类型
     * @param a 集合a
     * @param b 集合b
     * @param supplier 结果集合的类型与集合容器生成方法，例如 LinkedHashSet::new
     * @return 返回 a 与 b 的交集
     */
    public static <T> Set<T> intersection(final Set<T> a, final Set<T> b, Supplier<Set<T>> supplier) {
        if (null == a || null == b || b.isEmpty()) {
            return Collections.emptySet();
        }
        return a.stream().filter(b::contains).collect(Collectors.toCollection(supplier));
    }

    /**
     * 计算 a 与 b 的并集
     * @param <T> 集合的元素类型
     * @param a 集合a
     * @param b 集合b
     * @param supplier 结果集合的类型与集合容器生成方法，例如 LinkedHashSet::new
     * @return 返回 a 与 b 的并集
     */
    public static <T> Set<T> union(final Set<T> a, final Set<T> b, Supplier<Set<T>> supplier) {
        Set<T> set = supplier.get();
        if (null != a && !a.isEmpty()) {
            set.addAll(a);
        }
        if (null != b && !b.isEmpty()) {
            set.addAll(b);
        }
        return set;
    }

    /**
     * 计算 a 与 b 的 差集，即 a - b。
     * @param <T> 列表的元素类型
     * @param a 列表a
     * @param b 列表b
     * @param supplier 结果列表的类型与集合容器生成方法，例如 ArrayList::new
     * @return 返回  a - b 的结果，如果 b 为空，则返回 a，如果 a 为空，则返回空列表
     */
    public static <T> List<T> subtract(final List<T> a, final List<T> b, Supplier<List<T>> supplier) {
        if (null == a || null == b || b.isEmpty()) {
            return null == a ? Collections.emptyList() : a;
        }
        return a.stream().filter(x -> !b.contains(x)).collect(Collectors.toCollection(supplier));
    }

    /**
     * 计算 a 与 b 的交集
     * @param <T> 集合的元素类型
     * @param a 集合a
     * @param b 集合b
     * @param supplier 结果集合的类型与集合容器生成方法，例如 LinkedHashSet::new
     * @return 返回 a 与 b 的交集
     */
    public static <T> List<T> intersection(final List<T> a, final List<T> b, Supplier<List<T>> supplier) {
        if (null == a || null == b || b.isEmpty()) {
            return Collections.emptyList();
        }
        return a.stream().filter(b::contains).collect(Collectors.toCollection(supplier));
    }

    /**
     * 计算 a 与 b 的并集
     * @param <T> 集合的元素类型
     * @param a 集合a
     * @param b 集合b
     * @param supplier 结果集合的类型与集合容器生成方法，例如 LinkedHashSet::new
     * @return 返回 a 与 b 的并集
     */
    public static <T> List<T> union(final List<T> a, final List<T> b, Supplier<List<T>> supplier) {
        List<T> set = supplier.get();
        if (null != a && !a.isEmpty()) {
            set.addAll(a);
        }
        if (null != b && !b.isEmpty()) {
            set.addAll(b);
        }
        return set;
    }

}
